package components {
	
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	public class Sphere extends MovieClip {
		
		private var boll:Sprite; // наши оси у сферы
		private var bodyBoll:Sprite; // объект который будет содержать оси и который мы будем крутить
		private var body:Sprite; // заливка для того что бы можно было вешать события миши на обект не прицеливаясь
		
		public var mcList:Array;
		private var d:Number = 300; 
		private var lasta:Number;
		private var lastb:Number;
		private var sa:Number;
		private var ca:Number;
		private var sb:Number;
		private var cb:Number;
		private var sc:Number;
		private var cc:Number;
		private var active:Boolean = false;
		private var tspeed:Number = 1;
		private var radius:Number = 150;
		private var dtr:Number = Math.PI/180;
		private var elementCount:Number;
		
		public var rotateMode:Boolean = true;
		
		public var activeElement:Topic;
		
		private var _root:MovieClip;
		
		public function Sphere(data:Array, parentMC:MovieClip, count:uint=10, radiusP:Number=30, elemCount:uint=0) {  		
			super();
			
			_root = parentMC;
			
			this.radius = radiusP;
			elementCount = elemCount;
			
			mcList = [];
			var i:int;
			
			for(i=0; i<data.length; i++) {
				mcList.push(new Topic(this, data[i]));
			}
			
			create(count);
		}
		
		private function create(count:uint=10):void {
			
			this.bodyBoll = new Sprite();
			this.body = new Sprite();
			var graphicsLocal:Graphics;
			for(var i:uint = 0; i<=count; i++) {
				this.boll = new Sprite();
				graphicsLocal = this.boll.graphics;
				graphicsLocal.lineStyle(2,0xeeeeef);
				graphicsLocal.drawCircle(0,0,radius);
				this.bodyBoll.addChild(this.boll);
//				this.boll.rotationY = (100 / count * (i + 1)) * 3.60; // поворачиваем каждую ось на долю круга из 360 градусов где доля шаг поворота.
			}
			
			//создаем заливку 
			this.body.graphics.beginFill(0x000000,0);
			this.body.graphics.drawCircle(0, 0, radius);
			this.body.graphics.endFill();
			this.body.addChild(this.bodyBoll);
			//this.body.useHandCursor = true;
			this.addChild(this.body);
			
			var phi:Number = 0;
			var theta:Number = 0;
			

			for(i=0; i<mcList.length; i++) {
				
				phi = Math.acos(-1+(2*(i+1)-1)/elementCount);
				theta = Math.sqrt(elementCount*Math.PI)*phi;
				
				mcList[i].cx = radius * Math.cos(theta)*Math.sin(phi);
				mcList[i].cy = radius * Math.sin(theta)*Math.sin(phi);
				mcList[i].cz = radius * Math.cos(phi);
				
				addChild(mcList[i]);
			}

			sineCosine(0,0,0);
			lasta = 1;
			lastb = 1;
			
			addEventListener(Event.MOUSE_LEAVE, mouseExitHandler);
			addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			addEventListener(Event.ENTER_FRAME, updateTags);
		}
		
		private function mouseExitHandler(e:Event):void {active = false;}
		private function mouseMoveHandler(e:MouseEvent):void {active = true;}
		
		private function updateTags(e:Event):void {
			
			if(rotateMode) {
				
				var a:Number;
				var b:Number;
				if(active) {
					a = (-Math.min( Math.max(mouseY, -d ), d ) / radius ) * tspeed;
					b = (Math.min( Math.max(mouseX, -d ), d ) /radius ) * tspeed;
				} else {
					a = lasta * 0.89;
					b = lastb * 0.89;
				}
				lasta = a;
				lastb = b;
				// if a and b under threshold, skip motion calculations to free up the processor
				if( Math.abs(a) > 0.01 || Math.abs(b) > 0.01 ){
					var c:Number = 0;
					sineCosine(a,b,c);
					// bewegen van de punten
					for(var j:Number=0; j<mcList.length; j++) {
						// multiply positions by a x-rotation matrix
						var rx1:Number = mcList[j].cx;
						var ry1:Number = mcList[j].cy * ca + mcList[j].cz * -sa;
						var rz1:Number = mcList[j].cy * sa + mcList[j].cz * ca;
						// multiply new positions by a y-rotation matrix
						var rx2:Number = rx1 * cb + rz1 * sb;
						var ry2:Number = ry1;
						var rz2:Number = rx1 * -sb + rz1 * cb;
						// multiply new positions by a z-rotation matrix
						var rx3:Number = rx2 * cc + ry2 * -sc;
						var ry3:Number = rx2 * sc + ry2 * cc;
						var rz3:Number = rz2;
						// set arrays to new positions
						mcList[j].cx = rx3;
						mcList[j].cy = ry3;
						mcList[j].cz = rz3;
						// add perspective
						mcList[j].per = d / (d+rz3);
						// setmc position, scale, alpha
						if(!mcList[j].isDragged) {
							mcList[j].x = rx3 * mcList[j].per;
							mcList[j].y = ry3 * mcList[j].per;
							mcList[j].scaleX = mcList[j].scaleY = mcList[j].per;
							mcList[j].alpha = mcList[j].per/2;
						}
					}
					//depthSort();
				}
			}
			//rotateMode = false;
		}
		
		private function sineCosine(a:Number, b:Number, c:Number):void {
			sa = Math.sin(a * dtr);
			ca = Math.cos(a * dtr);
			sb = Math.sin(b * dtr);
			cb = Math.cos(b * dtr);
			sc = Math.sin(c * dtr);
			cc = Math.cos(c * dtr);
		}
		
		public function setActiveElement(element:Topic):void {
			activeElement = element;
		}
		
		public function dropElement():void {
			_root.dropElement
		}
		
		public function update(data:Array):void {

			/*var oldIdArray:Array = new Array();
			var newIdArray:Array = new Array();
			var addArray:Array = new Array();
			var deleteArray:Array = new Array();
			
			var i:int;
			var br:Broadcast;
			var t:Topic;
			
			for each(br in data)
				newIdArray.push(br.id);
			for each(t in mcList)
				oldIdArray.push(t.broadcast.id);
			
			for(i=0; i<newIdArray.length; i++)
				if(oldIdArray.indexOf(newIdArray[i]) == -1)
					addArray.push(data[i]);
			
			for(i=0; i<oldIdArray.length; i++)
				if(newIdArray.indexOf(oldIdArray[i]) == -1)
					deleteArray.push(i);
			
			for each(br in addArray)
				addElement(br);
				
			for (i=0; i<deleteArray.length; i++) {
				removeElement(deleteArray[i], deleteArray[i] - i);
			}
			*/
			
			var t:Topic;
			for each(t in mcList)
				removeChild(t);				
			mcList = new Array();
			
			var b:Broadcast;
			for each (b in data)
				mcList.push(new Topic(this, b));
			elementCount = mcList.length;
				
			var phi:Number = 0;
			var theta:Number = 0;
			
			var i:int;
			for(i=0; i<mcList.length; i++) {
				
				phi = Math.acos(-1+(2*(i+1)-1)/elementCount);
				theta = Math.sqrt(elementCount*Math.PI)*phi;
				
				mcList[i].cx = radius * Math.cos(theta)*Math.sin(phi);
				mcList[i].cy = radius * Math.sin(theta)*Math.sin(phi);
				mcList[i].cz = radius * Math.cos(phi);
				
				addChild(mcList[i]);
			}
			
			sineCosine(0,0,0);
			lasta = 1;
			lastb = 1;
		}
		
		public function updateData(data:Array):void {
			
			var phi:Number = 0;
			var theta:Number = 0;
			var i:int;
			for(i=0; i<mcList.length; i++) {
				
				trace(elementCount);
				phi = Math.acos(-1+(2*(i+1)-1)/elementCount);
				theta = Math.sqrt(elementCount*Math.PI)*phi;
				
				mcList[i].cx = radius * Math.cos(theta)*Math.sin(phi);
				mcList[i].cy = radius * Math.sin(theta)*Math.sin(phi);
				mcList[i].cz = radius * Math.cos(phi);
				
				addChild(mcList[i]);
			}	
		}
		
		private function addElement(broadcast:Broadcast):void {
			
			var topic:Topic = new Topic(this,broadcast);
			mcList.push(topic);
			
			elementCount = mcList.length;
			
			var phi:Number = 0;
			var theta:Number = 0;
			
			phi = Math.acos((elementCount-1)/elementCount);
			//phi = Math.acos(-1+(2*(i+1)-1)/elementCount);

			theta = Math.sqrt(elementCount*Math.PI)*phi;
			
			topic.cx = radius * Math.cos(theta)*Math.sin(phi);
			topic.cy = radius * Math.sin(theta)*Math.sin(phi);
			topic.cz = radius * Math.cos(phi);
			
			addChild(topic);
			//sineCosine(0,0,0);
			
		}
		
		private function removeElement(index:Number, chIndex:Number):void {
			mcList[index].remove(chIndex);
		}
				
		// override rotation functions
		/*override public function get rotationX():Number { return this.bodyBoll.rotationX; }
		override public function set rotationX(value:Number):void { this.bodyBoll.rotationX = value; }
		
		override public function get rotationY():Number { return this.bodyBoll.rotationY; }
		override public function set rotationY(value:Number):void { this.bodyBoll.rotationY = value; }
		
		override public function get rotationZ():Number { return this.bodyBoll.rotationZ; }
		override public function set rotationZ(value:Number):void { this.bodyBoll.rotationZ = value; }*/
		
	}
}

